// /////////////////////////////////////////////////////////////////////////////
//
// Name:            asEntityComponent.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Binds the EntityComponent class to AngelScript
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "asEntityComponent.h"

#ifdef __COMPILE_WITH_ANGELSCRIPT__

#include "../ScriptHelper.h"

#include "../../core/GameManager.h"


// ScriptedEntityComponent class
// ScriptedEntityComponent constructor
ScriptedEntityComponent::ScriptedEntityComponent(asIScriptObject *object)
: EntityComponent(NULL), mObject(object)
{
    // No new state was created, so lets fix the IDs.
    mIDCount--;

    // Set up pointers which will be used.
    mObject->AddRef();
    mContext = GameManager::Instance()->getScriptManager()->getEngine()->CreateContext();

    // Retrieve data from the scripted EntityComponent.
    int id;

    // Get ID.
    id = mObject->GetObjectType()->GetMethodIdByDecl("u32 getID()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
    mID = mContext->GetReturnDWord();

    // Get the name.
    id = mObject->GetObjectType()->GetMethodIdByDecl("const string getName()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
    mName = *reinterpret_cast<std::string*>(mContext->GetReturnObject());

    // Get the parent.
    id = mObject->GetObjectType()->GetMethodIdByDecl("Entity@ getParent()");

    mContext->Prepare(id);
    mContext->SetObject(mObject);
    mContext->Execute();
    Entity *parent = reinterpret_cast<Entity*>(mContext->GetReturnObject());

    if(parent != NULL)
    {
       if(parent->addComponent(this))
       {
         pParent = parent;
         parent->grab();
       }

       else pParent = NULL;
    }

    else pParent = NULL;
}

// ScriptedEntityComponent deconstructor
ScriptedEntityComponent::~ScriptedEntityComponent()
{
    mContext->Release();
    mObject->Release();
}


//! Reference factory for the EntityComponent class.
EntityComponent* createEntityComponent(Entity* parent)
{
    return new EntityComponent(parent);
}

//! Binds the EntityComponent class to AngelScript.
void bindEntityComponent(asIScriptEngine *engine)
{
    // Forward declarations.
    int r;

    // Bind EntityComponent class (and dependencies).
    r = engine->RegisterObjectType("EntityComponent", sizeof(EntityComponent), asOBJ_REF);
    r = engine->RegisterObjectType("Entity", sizeof(Entity), asOBJ_REF);

    // Get EntityComponent base functions.
    bindEntityComponentBase<EntityComponent>(engine, "EntityComponent");

    // Set EntityComponent behaviour.
    r = engine->RegisterObjectBehaviour("EntityComponent", asBEHAVE_FACTORY, "EntityComponent@ f(Entity @+)",
                                        asFUNCTION(createEntityComponent), asCALL_CDECL); assert(r >= 0);

    r = engine->RegisterObjectMethod("EntityComponent", "EntityComponent& opAssign(const EntityComponent &in)",
                                     asFUNCTION(assignT<EntityComponent>), asCALL_CDECL_OBJFIRST); assert(r >= 0);

    // Define the interface for inheritance.
    r = engine->RegisterInterface("IEntityComponent");

    r = engine->RegisterInterfaceMethod("IEntityComponent", "u32 getID()");
    r = engine->RegisterInterfaceMethod("IEntityComponent", "const string getName()");
    r = engine->RegisterInterfaceMethod("IEntityComponent", "Entity@ getParent()");

    // Define the class for inheritance.
    std::string decl = "class CEntityComponent : IEntityComponent, IHasSlots\n"
                       "{\n"
                       "    EntityComponent @_inner;\n"
                       "    Entity @pParent;\n"
                       "    string mName;\n"
                       "\n"
                       "    CEntityComponent(Entity @parent)\n"
                       "    {\n"
                       "       @_inner = EntityComponent(null);\n"
                       "\n"
                       "       @pParent = @parent;\n"
                       "       pParent.addComponent(this);\n"
                       "    }\n"
                       "\n"
                       "    u32 getID() { return _inner.getID(); }\n"
                       "    const string getName() { return mName; }\n"
                       "    Entity@ getParent() { return pParent; }\n"
                       "}\n";

    GameManager::Instance()->getScriptManager()->addScriptSection("CEntityComponent", decl);
}

#endif // __COMPILE_WITH_ANGELSCRIPT__

// End of File
